#!/bin/sh

pic_driver=igb_uio
pic_driver=vfio-pci
pic_driver=uio_pci_generic
modprobe $pic_driver
mkdir -p /etc/pci_bind

restore() {
    while read line; do
        pci_num=`echo $line | awk -F= '{ print $1 }'`;  [ ! -z "$pci_num" ] || continue
        mac=`echo $line | awk -F= '{ print $2 }'`;      [ ! -z "$mac"     ] || continue
        inf=`grep "${pci_num}=" /etc/pci_bind/pci_interface_list | awk -F= '{ print $2 }'`; [ ! -z "$inf" ] || continue
        driver=`grep "${pci_num}=" /etc/pci_bind/pci_driver_list | awk -F= '{ print $2 }'`
        cur_driver=`find /sys/bus/pci/drivers/ -name $pci_num | tr '/' ' ' | awk '{ print $5 }'`
        if [ ! "x$cur_driver" = "x$driver" ]; then
            echo "unbind: pci $pci_num $pic_driver -> $driver [$inf $mac]"
            echo $pci_num >/sys/bus/pci/drivers/$cur_driver/unbind
            if [ -f /sys/bus/pci/devices/${pci_num}/driver_override ]; then
                echo ${driver} > /sys/bus/pci/devices/${pci_num}/driver_override
            else
                Vendor=`lspci -s $pci_num -Dvmn | grep '^Vendor' | awk '{print $2}'`
                Device=`lspci -s $pci_num -Dvmn | grep '^Device' | awk '{print $2}'`
                echo "0x${Vendor}" "0x${Device}" > /sys/bus/pci/drivers/${driver}/new_id
            fi
            echo $pci_num >/sys/bus/pci/drivers/${driver}/bind
            sleep 0.1
            nameif $inf $mac
        fi
        ifconfig $inf up
    done </etc/pci_bind/pci_mac_list
}

bind() {
    for inf in $*; do
        [ ! -z ${inf} ] || continue
        pci_num=`grep "${inf}$" /etc/pci_bind/pci_interface_list | awk -F= '{ print $1 }'`; [ ! -z "$pci_num" ] || continue
        [ ! -z ${pci_num} ] || continue
        cur_driver=`find /sys/bus/pci/drivers/ -name $pci_num | tr '/' ' ' | awk '{ print $5 }'`
        echo "bind: $inf $pci_num $cur_driver -> $pic_driver"
        if [ -f /sys/bus/pci/devices/${pci_num}/driver_override ]; then
            echo $pic_driver > /sys/bus/pci/devices/${pci_num}/driver_override
        else
            Vendor=`lspci -s $pci_num -Dvmn | grep '^Vendor' | awk '{print $2}'`
            Device=`lspci -s $pci_num -Dvmn | grep '^Device' | awk '{print $2}'`
            echo "0x${Vendor}" "0x${Device}" > /sys/bus/pci/drivers/$pic_driver/new_id
        fi
        [ x${cur_driver} = x ] || echo $pci_num >/sys/bus/pci/drivers/${cur_driver}/unbind
        echo $pci_num >/sys/bus/pci/drivers/$pic_driver/bind
    done
}

list() {
    echo "curr stats:"
    while read line; do
        pci_num=`echo $line | awk -F= '{ print $1 }'`;                             [ ! -z "$pci_num" ] || continue
        mac=`echo $line | awk -F= '{ print $2 }'`;                                 [ ! -z "$mac"     ] || continue
        inf=`grep "${pci_num}=" /etc/pci_bind/pci_interface_list | awk -F= '{ print $2 }'`; [ ! -z "$inf"     ] || continue
        driver=`grep ${pci_num} /etc/pci_bind/pci_driver_list`
        driver=`echo $driver | awk -F= '{ print $2 }'`
        cur_driver=`find /sys/bus/pci/drivers/ -name $pci_num | tr '/' ' ' | awk '{ print $5 }'`
        echo $inf $mac $driver $cur_driver | awk '{printf("%-17s %s    raw_driver %-17s cur_driver %s\n", $1, $2, $3, $4)}'
    done </etc/pci_bind/pci_mac_list
}


if [ ! -s /etc/pci_bind/pci_driver_list ]; then
    for i in `lspci | grep 'Ethernet controller' | awk '{print $1}'`; do
        find /sys/bus/pci/drivers/ -name 0000:$i | tr '/' ' ' | awk '{ printf "%s=%s\n",$6,$5 }' >>/etc/pci_bind/pci_driver_list
        #find /sys/bus/pci/drivers/ -name 0000:$i | tr '/' ' ' | awk '{ printf "%s=%s\n",$6,$5 }'
    done
    [ -s /etc/pci_bind/pci_driver_list ] || { echo "fail to generate /etc/pci_bind/pci_driver_list"; exit 1; }
fi
echo "#######################"
echo "###  pci_driver_list:"
while read line; do
    [ "x$line" = "x" ] && continue;
    echo "###  $line"
done </etc/pci_bind/pci_driver_list


if [ ! -s /etc/pci_bind/pci_interface_list ]; then
    for pci_num in `lspci | grep 'Ethernet controller' | awk '{print $1}'`; do
        line=`find /sys/bus/pci/drivers/ -name 0000:$pci_num`
        inf=`ls $line/net`
        echo "0000:$pci_num=$inf" >>/etc/pci_bind/pci_interface_list
    done
    [ -s /etc/pci_bind/pci_interface_list ] || { echo "fail to generate /etc/pci_bind/pci_interface_list"; exit 1; }
fi
echo "#######################"
echo "###  pci_interface_list:"
while read line; do
    [ "x$line" = "x" ] && continue;
    echo "###  $line"
done </etc/pci_bind/pci_interface_list

if [ ! -s /etc/pci_bind/pci_mac_list ]; then
    for i in `lspci | grep 'Ethernet controller' | awk '{print $1}'`; do
        inf=`grep "0000:${i}=" /etc/pci_bind/pci_interface_list | awk -F= '{ print $2 }'`
        if [ "x$inf" = "x" ]; then
            echo "not found interface name for pic 0000:${i}, is 0000:${i} already bond to other driver?"
        fi
        echo -n "0000:${i}=" >>/etc/pci_bind/pci_mac_list
        ip link | grep -v altname | awk '{print $2}' | sed '/:$/{N;s/:\n/=/}' | grep -e "^$inf=" | awk -F= '{print $2}' >>/etc/pci_bind/pci_mac_list
        echo "" >>/etc/pci_bind/pci_mac_list
    done
fi
echo "#######################"
echo "###  pci_mac_list:"
while read line; do
    [ "x$line" = "x" ] && continue;
    echo "###  $line"
done </etc/pci_bind/pci_mac_list
echo "#######################"

case "x$1" in
    "xrestore")
        shift
        restore
        list
        ;;
    "xbind")
        shift
        bind $*
        list
        ;;
    "xlist")
        list
        ;;
    *)
        echo "usage: $0 list"
        echo "usage: $0 bind eth2 eth3 eth4"
        echo "usage: $0 restore"
        exit 1;
esac
